/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <stdio.h>

#include <string>
#include <iostream>

class Response {
 public:

  // static XxxResponse create();
#define IMPLEMENT_CLASSNAME(typeName) \
  static const char* className() {    \
    return #typeName;                 \
  }
};

template<class T>
class Request {
 public:

};

// depends on T::className() T::create()
template<class T>
T getResponse(Request<T>& request) {
  std::cout << T::className() << std::endl;
  return T::create();
}

///////////////////////////////////////////////////////////////
// detail ....
class FooResponse : public Response {
 public:
  FooResponse() {
    std::cout << "FooResponse_" << this << " created!\n";
  }

  ~FooResponse() {
    std::cout << "FooResponse_" << this << " destroy!\n";
  }

  static FooResponse create() {
    FooResponse resp;
    return resp;
  }

  IMPLEMENT_CLASSNAME(FooResponse)
};

class FooRequest : public Request<FooResponse> {
 public:
};

class BarResponse : public Response {
 public:
  BarResponse() {
    std::cout << "BarResponse_" << this << " created!\n";
  }

  ~BarResponse() {
    std::cout << "BarResponse_" << this << " destroy!\n";
  }

  static BarResponse create() {
    BarResponse resp;
    return resp;
  }

  IMPLEMENT_CLASSNAME(BarResponse)
};

class BarRequest : public Request<BarResponse> {
 public:

};

int main() {
  FooRequest foo;
  FooResponse fooRes = getResponse(foo);

  BarRequest bar;
  BarResponse barRes = getResponse(bar);
  return 0;
}

